#include "loop_action.h"

#include <boost/pool/singleton_pool.hpp>

namespace anb { namespace net {

loop_action::loop_action(type type) {
	m_type = type;
}

loop_action::~loop_action() {
}

loop_action::type loop_action::get_type() {
	return m_type;
}

typedef boost::singleton_pool<packet_write, sizeof(packet_write)> packet_pool;

loop_action* loop_action::create(type type) {
	loop_action* action;
	switch (type)
	{
	case type_write_packet: {
		void* ptr = packet_pool::malloc();
		packet_write* pw = new (ptr)packet_write();
		action = pw;
		break;
	}
	default: {
		action = NULL;
		break;
	}
	}
	return action;
}

void loop_action::destroy(loop_action* action) {
	if (!action) {
		return;
	}
	switch (action->get_type())
	{
	case loop_action::type_write_packet: {
		((packet_write*)action)->~packet_write();
		packet_pool::free(action);
		break;
	}
	default: {
		action = NULL;
		break;
	}
	}
}

void loop_action::async_callback(uv_async_t* async) {
	loop_action* action = (loop_action*)async->data;
	action->act();
}

write::write(type type) : loop_action(type) {
}

write::~write() {
}

void write::init(connection_base::ptr connection) {
	m_connection = connection;
}

void write::act() {
	m_connection->send(this);
}

uv_write_t* write::get_write() {
	return &m_write;
}

packet_write::packet_write() : write(type_write_packet) {
	m_bufs[index_len].base = m_len;
	m_bufs[index_len].len = connection_base::LEN_SIZE;
	m_bufs[index_packet].base = m_packet;
	m_bufs[index_packet].len = packet::SIZE;
	m_bufs[index_body].base = NULL;
	m_bufs[index_body].len = 0;
}

packet_write::~packet_write() {
	uv_buf_t* body = &m_bufs[index_body];
	if (body->base) {
		anb::common::utils::free(body->base);
		body->base = NULL;
	}
}

void packet_write::init(connection_base::ptr connection, size_t body_len) {
	write::init(connection);
	m_bufs[index_body].base = body_len > 0 ? (char*)anb::common::utils::malloc(body_len) : NULL;
	m_bufs[index_body].len = body_len;

	size_t len = connection_base::LEN_SIZE + packet::SIZE + body_len;
	m_len[0] = (len >> 24) & 0xff;
	m_len[1] = (len >> 16) & 0xff;
	m_len[2] = (len >> 8) & 0xff;
	m_len[3] = (len)& 0xff;
}

size_t packet_write::size() {
	return index_max;
}

uv_buf_t* packet_write::get() {
	return m_bufs;
}

char* packet_write::get_packet() {
	return m_bufs[index_packet].base;
}

char* packet_write::get_body() {
	return m_bufs[index_body].base;
}

}
}
